home *** CD-ROM | disk | FTP | other *** search
- Subject: Routines to check the load average
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 4, Issue 78
- Submitted by: genrad!decvax!trwrb!jsb
-
- Here are some routines I wrote that will allow any program
- to check on the load average without themselves having to have
- permission to read /dev/kmem.
-
- John Bien
- decvax!trwrb!jsb
-
- ------------------------ Cut Here ---------------------------
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # README
- # Makefile
- # example.c
- # getld.c
- # getload.3
- # getload.c
- # loadstuff.h
- # u_getloads.c
- # This archive created: Fri Apr 25 07:20:24 1986
- export PATH; PATH=/bin:$PATH
- echo shar: extracting "'README'" '(1513 characters)'
- if test -f 'README'
- then
- echo shar: will not over-write existing file "'README'"
- else
- cat << \SHAR_EOF > 'README'
- Here are 2 library funtions that will allow non-setuid (or setgid)
- functions to check the load average. They are:
-
- getload(): A fast routine which will return only
- the 1, 5, or 15 minute average. It only returns
- 1 decimal place of accuracy (ie 3.1 instead of 3.08) and
- will only tell load averages below 25.0
- It requires a program installed on the system called
- "getld". This setgid program reads /dev/kmem and
- exits with information we need.
- ugetloads(): A much slower routine that will return all 3 load
- averages via an array passed to it. It just
- runs uptime(1) and captures the information it needs from
- there not requiring the external program getld.
-
-
- If getload() is usable (ie you install the program "getld")
- it is much faster than ugetloads() and can be called 3 times
- (to get the 3 load averages) in much less time than ugetloads()
- can be called once. The speed of getload() lies in the fact that "getld"
- exits() with the load average we want instead of printing
- it. This way getload() doesn't have to open a pipe to read what "getld" might
- otherwise print, it just has to look at the high byte of the exit status.
-
- The routine ugetloads() allows anyone to get the load averages
- without any extra programs on the system. It's good if you don't happen
- to be super-user and can let "getld" read /dev/kmem.
-
- A sample program example.c demonstrates the use of these routines.
-
- John Bien
- {ihnp4 | ucbvax | decvax}!trwrb!jsb
-
- SHAR_EOF
- if test 1513 -ne "`wc -c < 'README'`"
- then
- echo shar: error transmitting "'README'" '(should have been 1513 characters)'
- fi
- fi
- echo shar: extracting "'Makefile'" '(880 characters)'
- if test -f 'Makefile'
- then
- echo shar: will not over-write existing file "'Makefile'"
- else
- cat << \SHAR_EOF > 'Makefile'
- # Makefile for load average routines.
- # John Bien
-
- # Define -DBSD41 if you are running 4.1 (only used in ugetload())
- CFLAGS = -O
- CC = cc
- RANLIB = ranlib
- LIBNAME = libload.a
- LIBDIR = /usr/local/lib
-
- # PROGDIR is where the setgid program getld will reside
- PROGDIR = /usr/local/lib
-
- # MEMGRP = the group that is allowed to read /dev/kmem
- MEMGRP = sys
-
- CFILES = getload.c u_getloads.c
- OFILES = getload.o u_getloads.o
-
- all: $(LIBNAME) getld
-
- $(LIBNAME): $(OFILES)
- ar rc $(LIBNAME) $(OFILES)
- $(RANLIB) $(LIBNAME)
-
- getld: getld.c
- $(CC) $(CFLAGS) -o getld getld.c
-
- example:
- $(CC) $(CFLAGS) -o example example.c $(LIBNAME)
-
- install: $(LIBNAME) getld
- cp $(LIBNAME) $(LIBDIR)
- $(RANLIB) $(LIBDIR)/$(LIBNAME)
- cp getld $(PROGDIR)
- chgrp $(MEMGRP) $(PROGDIR)/getld
- chmod 2111 $(PROGDIR)/getld
-
- shar:
- shar README getload.3 Makefile getld.c loadstuff.h \
- $(CFILES) example.c > Shar
- SHAR_EOF
- if test 880 -ne "`wc -c < 'Makefile'`"
- then
- echo shar: error transmitting "'Makefile'" '(should have been 880 characters)'
- fi
- fi
- echo shar: extracting "'example.c'" '(874 characters)'
- if test -f 'example.c'
- then
- echo shar: will not over-write existing file "'example.c'"
- else
- cat << \SHAR_EOF > 'example.c'
- main()
- {
- float getload(), average;
- float aves[3];
-
- average = getload(1);
- if((int)average == -99)
- puts("1 minute average is greater than 25.0");
- else if(average < 0)
- puts("Error using getload");
- else
- printf("One minute average is %.1f\n",average);
-
- average = getload(5);
- if((int)average == -99)
- puts("5 minute average is greater than 25.0");
- else if(average < 0)
- puts("Error using getload");
- else
- printf("Five minute average is %.1f\n",average);
-
- average = getload(15);
- if((int)average == -99)
- puts("15 minute average is greater than 25.0");
- else if(average < 0)
- puts("Error using getload");
- else
- printf("Fifteen minute average is %.1f\n",average);
-
- ugetloads(aves);
-
- printf("And using ugetloads, the load averages are: %.2f, %.2f, %.2f\n",
- aves[0], aves[1], aves[2]);
- }
- SHAR_EOF
- if test 874 -ne "`wc -c < 'example.c'`"
- then
- echo shar: error transmitting "'example.c'" '(should have been 874 characters)'
- fi
- fi
- echo shar: extracting "'getld.c'" '(1511 characters)'
- if test -f 'getld.c'
- then
- echo shar: will not over-write existing file "'getld.c'"
- else
- cat << \SHAR_EOF > 'getld.c'
- /* getld.c
- * This program must be setgid to memory (or whoever is allowed
- * to read /dev/kmem). It exits with with the load average, or
- * a negative number to indicate an error.
- * It serves primarily to be called by the library routine
- * getload();
- */
-
- #include <stdio.h>
- #include <nlist.h>
- #include "loadstuff.h"
-
- struct nlist avenrun[] =
- {
- { "_avenrun" },
- { 0 }
- };
-
- main(argc,argv)
- int argc;
- char **argv;
- {
-
- register int kmem, whatave, returnave;
- double avg[3];
-
- if((kmem = open("/dev/kmem", 0)) < 0)
- exit(NOKMEM);
-
- nlist(NAMELIST, avenrun); /* Find where our kernel keeps it */
- if(avenrun[0].n_type == 0)
- exit(NONAMELST);
-
- whatave = atoi(argv[1]);
- --whatave;
- if(whatave == 4) whatave = 1;
- if(whatave == 14) whatave = 2;
-
- if(whatave <0 || whatave > 2)
- whatave = 0;
-
- lseek(kmem, (long) avenrun[0].n_value, 0);
- read(kmem, avg, sizeof (avg));
-
- returnave = avg[whatave] * 100;
- /* Now we have the load average to 2 floating point accuracy * 100
- * However, we want to return it with 1 point accuracy that is correctly
- * rounded up or down. So we divide it by 10 and see what the
- * remainder is and do the rounding (for the integer).
- */
- if(returnave % 10 >= 5) /* Round up */
- returnave = returnave / 10 + 1;
- else returnave = returnave / 10;
-
- if(returnave >= 250) /* We cannot return with a number > 255 */
- returnave = 250; /* and 255 = -1, 254 = -2 */
-
- exit(returnave); /* Exit with an integer load average */
-
- }
- SHAR_EOF
- if test 1511 -ne "`wc -c < 'getld.c'`"
- then
- echo shar: error transmitting "'getld.c'" '(should have been 1511 characters)'
- fi
- fi
- echo shar: extracting "'getload.3'" '(1320 characters)'
- if test -f 'getload.3'
- then
- echo shar: will not over-write existing file "'getload.3'"
- else
- cat << \SHAR_EOF > 'getload.3'
- .TH GETLOAD 3-local
- .SH NAME
- getload, ugetload \- load average routines
- .SH SYNOPSIS
- .nf
- .B float getload(whatave)
- .B int whatave;
- .PP
- .B ugetloads(aves)
- .B float aves[3];
- .fi
- .SH DESCRIPTION
- These functions allows any program to find what the current
- load averages are.
- .PP
- .I Getload()
- returns the 1, 5, or 15 minute load average.
- .I Ugetloads()
- puts the 1, 5, and 15 load averages into the array passed to
- it.
- .I Getload()
- is much faster than
- .I ugetloads()
- and can be invoked 3 times (to return all 3 load averages) in much
- less time than
- .I ugetloads()
- can be invoked once.
- .I Getload()
- can only return a load average between 0.0 and 25.0, which should
- be fine for most applications.
- .SH FILES
- .B /usr/local/lib/getld \-
- The program that actually reads /dev/kmem for
- .I getload()
- .br
- .B uptime(1) \-
- The program that reads /dev/kmem for
- .I ugetload()
- .SH DIAGNOSTICS
- .I Getload()
- returns:
- .RS
- -99 if the load average is over 25.0
- .br
- -2 if the program
- .B /usr/local/lib/getld
- could not read
- .B /dev/kmem
- .br
- -1 if
- .B /usr/local/lib/getld
- could not read the namelist (\fB/vmunix\fR).
- .SH BUGS
- The function
- .I getload()
- will return a load average of 12.7 if it couldn't execute
- the program
- .B /usr/local/lib/getld.
- .SH AUTHOR
- John Bien
- .br
- UUCP: {ihnp4 | ucbvax | decvax}!trwrb!jsb
- .SH DATE
- April 1986
- SHAR_EOF
- if test 1320 -ne "`wc -c < 'getload.3'`"
- then
- echo shar: error transmitting "'getload.3'" '(should have been 1320 characters)'
- fi
- fi
- echo shar: extracting "'getload.c'" '(1245 characters)'
- if test -f 'getload.c'
- then
- echo shar: will not over-write existing file "'getload.c'"
- else
- cat << \SHAR_EOF > 'getload.c'
- /* getload(what)
- * int what;
- *
- * Returns the 1, 5, or 15 minute load average.
- * Call with getload(1), or getload(5), or getload(15).
- * Defaults to getload(1);
- * The program "getld" must be setgid to read /dev/kmem and
- * located where the execl expects it (/usr/local/lib).
- */
- #include <signal.h>
- #include "loadstuff.h"
-
- float getload(whatave)
- int whatave;
- {
- int loadav;
- float load;
- char *charav = "1 ";
- int status, pid, w;
-
- if(whatave == 15)
- charav = "15";
- if (whatave == 5)
- charav = "5";
-
- /* Now run the getld program, using fork/exec. */
- if ((pid = vfork()) == 0) {
- /* This Line should be changed if the program "getld" is not
- * going to be actually called "getld" or wont be in /usr/local/lib
- */
- execl("/usr/local/lib/getld","getld",charav,0);
- _exit(254);
- }
- while ((w = wait(&status)) != pid && w != -1)
- ;
- if (w == -1)
- status = -1;
-
- loadav = (status >> 8); /* Set loadav to system exit */
-
- load = (float)loadav / 10; /* Get the correct floating point value */
- /* that corresponds to the integer */
- /* exit value we received from getld */
-
- if(loadav == 254) load = NOKMEM;
- if(loadav == 255) load = NONAMELST;
- if(loadav == 250) load = OVERFLOW;
-
- return(load);
- }
- SHAR_EOF
- if test 1245 -ne "`wc -c < 'getload.c'`"
- then
- echo shar: error transmitting "'getload.c'" '(should have been 1245 characters)'
- fi
- fi
- echo shar: extracting "'loadstuff.h'" '(87 characters)'
- if test -f 'loadstuff.h'
- then
- echo shar: will not over-write existing file "'loadstuff.h'"
- else
- cat << \SHAR_EOF > 'loadstuff.h'
- #define NOKMEM -2
- #define NONAMELST -1
- #define OVERFLOW -99
- #define NAMELIST "/vmunix"
- SHAR_EOF
- if test 87 -ne "`wc -c < 'loadstuff.h'`"
- then
- echo shar: error transmitting "'loadstuff.h'" '(should have been 87 characters)'
- fi
- fi
- echo shar: extracting "'u_getloads.c'" '(876 characters)'
- if test -f 'u_getloads.c'
- then
- echo shar: will not over-write existing file "'u_getloads.c'"
- else
- cat << \SHAR_EOF > 'u_getloads.c'
- /* ugetloads(ls)
- * fload ld[3];
- *
- * Puts the 1, 5, and 15 minute load averages in the float
- * array passed to it. This program calls upon uptime(1)
- * which could have different ways of printing ie. with bsd4.2
- * " 9:34pm up 11 hrs, 3 users, load average: 0.25, 0.22, 0.24 "
- * notice the commas -- ^ --- ^.
- * while bsd4.1 does not print commas. The BSD41 define will
- * take care of this if that is your system, it defaults to
- * the 4.2 version.
- */
-
- #include <stdio.h>
-
- FILE *popen();
-
- ugetloads(ld)
- float ld[3];
- {
- FILE *stream;
-
- if((stream = popen("/usr/ucb/uptime","r")) == NULL)
- return(-1);
-
- #ifdef BSD41
- fscanf(stream,"%*[^l] load average: %f %f %f", &ld[0],&ld[1],&ld[2]);
- #else
- fscanf(stream,"%*[^l] load average: %f, %f, %f", &ld[0],&ld[1],&ld[2]);
- #endif BSD41
- pclose(stream);
- return(NULL);
- }
-
- SHAR_EOF
- if test 876 -ne "`wc -c < 'u_getloads.c'`"
- then
- echo shar: error transmitting "'u_getloads.c'" '(should have been 876 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-